#!/user/bin/env python
# -*- coding:utf-8 -*-
# author : 洛月
# mailer  : 2870093961@qq.com
# created: 2023-03-27 23:18
# updated: 2023-03-27 23:18


from PIL import Image, ImageDraw, ImageFont
from typing import Tuple, Union
from utils import files
from lxml import etree
from pathlib import Path
from io import BytesIO
import re

CURRENT_FOLDER = Path(__file__).absolute().parent


def save_icon(data: bytes, path: Union[str, Path], size: Tuple[int, int] = (128, 128)) -> Path:
    return save(data=data, path=path, size=size)


def save(data: bytes, path: Union[str, Path], name: Union[str, None] = None, size: Union[Tuple[int, int], None] = None,
         format_: str = "webp", quality: int = 95) -> Path:
    """保存图片"""
    img = Image.open(BytesIO(data))

    if size is not None:
        img = img.resize(size)

    if name is None:
        name = f"{files.get_hash_by_bytes(data)}.{format_}"
    else:
        name = f"{name}.{format_}"

    if isinstance(path, str):
        path = Path(path)

    file_path = path / name
    img.save(file_path, format=format_, quality=quality)

    return file_path


def create_fiction_cover(name: str, author: str, type_: int) -> BytesIO:
    """生成小说封面"""
    # 读取字体文件
    font1 = ImageFont.truetype(f"{CURRENT_FOLDER}/font/文悦周华金新魏体.ttf", 50, encoding="utf-8")
    font2 = ImageFont.truetype(f"{CURRENT_FOLDER}/font/汉仪空山楷 W.ttf", 30, encoding="utf-8")
    # 读取封面背景
    bg = Image.open(f"{CURRENT_FOLDER}/cover/{type_}.png")

    draw = ImageDraw.Draw(bg)

    # 超过24个字符截取前23个字符
    if len(name) > 24:
        name = name[0:23] + "…"
    # 分行
    lines = [name[i:i + 8] for i in range(0, len(name), 8)]
    # 确定Y轴起始点
    start_y = 480 + (3 - len(lines)) * 30
    for index, line in enumerate(lines):
        draw.text(xy=((600 - len(line) * 50) / 2, start_y + index * 60), text=line, font=font1, fill=(31, 34, 39, 255))

    author += " 著"
    # x:（背景宽度 - 文本占用宽度）/ 2 + 15（半个字符宽度）
    draw.text(xy=((600 - len(author) * 30) / 2 + 15, 700), text=author, font=font2, fill=(154, 156, 161, 255))

    bg = bg.resize((360, 480))

    byte = BytesIO()
    bg.save(byte, format="webp")

    return byte


def handle_fiction_cover(blob: bytes) -> BytesIO:
    """处理小说封面
    1. 统一图片像素
    2. 统一图片格式
    """
    img = Image.open(BytesIO(blob))
    img = img.resize((360, 480))
    byte = BytesIO()
    img.save(byte, format="webp")
    return byte


def is_svg(data: Union[str, bytes]) -> bool:
    """判断是否为有效的SVG文件"""
    if isinstance(data, bytes):
        data = data.decode("utf-8")
    return re.match(r"^<(\?xml |svg )(.|\n)+</svg>$", data) is not None


def optimize_svg(data: Union[str, bytes]) -> bytes:
    if isinstance(data, str):
        data = data.encode("utf-8")
    parser = etree.XMLParser(remove_blank_text=True, ns_clean=True, remove_pis=True, remove_comments=True)
    svg_etree = etree.fromstring(data, parser)

    text = etree.tostring(svg_etree, pretty_print=True).decode("utf-8")
    for char in ["\t", "\n"]:
        text = text.replace(char, "")

    return text.encode("utf-8")


def save_svg(data: Union[str, bytes], path: Union[str, Path], optimize: bool = False) -> None:
    """格式化SVG并保存"""
    if optimize:
        data = optimize_svg(data)
    svg_text: str = ""
    if isinstance(data, bytes):
        svg_text = data.decode("utf-8")
    elif isinstance(data, str):
        svg_text = data

    if is_svg(svg_text):
        with open(path, 'w') as fp:
            fp.write(svg_text)
    else:
        raise "is not a valid svg"


class SVG:
    content: Union[str, None] = None
    _parser = etree.XMLParser(remove_blank_text=True, ns_clean=True, remove_pis=True, remove_comments=True)

    def __init__(self, data: Union[str, bytes, Path], optimize=False):
        if isinstance(data, str):
            self.content = data
        elif isinstance(data, bytes):
            self.content = data.decode("utf-8")
        elif isinstance(data, Path):
            with open(data, "r", encoding="utf-8") as fp:
                self.content = fp.read()
        if optimize:
            optimize_svg(data)

    @property
    def is_svg(self) -> bool:
        """判断是否为有效的SVG文件"""
        return re.match(r"^<(\?xml |svg )(.|\n)+</svg>$", self.content) is not None

    def optimize_svg(self) -> None:
        svg_etree = etree.fromstring(self.content, self._parser)

        svg_text = etree.tostring(svg_etree, pretty_print=True).decode("utf-8")
        for char in ["\t", "\n"]:
            svg_text = svg_text.replace(char, "")

        self.content = svg_text

    def save(self, path: Union[str, Path], name: Union[str, None] = None) -> Path:
        """格式化SVG并保存"""

        if name is None:
            name = f"{files.get_hash_by_bytes(self.content.encode('utf-8'))}.svg"
        else:
            name = f"{name}.svg"

        if isinstance(path, str):
            path = Path(path)
        file_path = path / name
        if self.is_svg:
            with open(file_path, 'w') as fp:
                fp.write(self.content)
        else:
            raise "is not a valid svg"

        return file_path

    @property
    def width(self) -> Union[int, None]:
        try:
            svg_etree = etree.fromstring(self.content, self._parser)

            width_property = svg_etree.xpath("./@width")
            if len(width_property) > 0:
                return int(width_property[0])

            view_box_property = svg_etree.xpath("./@viewBox")
            if len(view_box_property) > 0:
                return int(view_box_property[0].split(" ")[2])
        except Exception as err:
            print(err)
            return None

    @property
    def height(self) -> Union[int, None]:
        try:
            svg_etree = etree.fromstring(self.content, self._parser)

            width_property = svg_etree.xpath("./@height")
            if len(width_property) > 0:
                return int(width_property[0])

            view_box_property = svg_etree.xpath("./@viewBox")
            if len(view_box_property) > 0:
                return int(view_box_property[0].split(" ")[3])
        except Exception as err:
            print(err)
            return None

    @property
    def hash(self) -> str:
        return files.get_hash_by_bytes(self.content.encode('utf-8'))

    @property
    def size(self) -> int:
        return len(self.content.encode("utf-8"))


if __name__ == '__main__':
    svg = SVG(r"E:\V4\web_server\static\images\1\3cf86cf1dbf86a00bc7197938bdd4030.svg")

    print(svg.is_svg)
